package net.rlair.esAnalyzeWord.service;

import net.rlair.esAnalyzeWord.model.HotWord;
import net.rlair.esAnalyzeWord.util.EsClientUtil;
import net.rlair.esAnalyzeWord.util.JsonMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * es curd操作.
 * @author yaoyi
 * @since 2018/03/19
 * @version 1.0.0.0
 */
@Service
public class EsClientService {

    /**
     * 日志.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(EsClientService.class);

    /**
     * index_name.
     */
    @Value("${elastic.index}")
    private String index;

    /**
     * type_name.
     */
    @Value("${elastic.type}")
    private String type;

    /**
     * 初始化es client,并查询集群健康状况.
     */
    @PostConstruct
    private void init(){
        if(!isHealth()){
            LOGGER.error(">>>>>>es集群处于非健康状态！");
        }
    }

    /**
     * 集群健康状况查询.
     * @return ClusterStatsResponse
     */
    public boolean isHealth(){
        final String s = EsClientUtil.getEsClusterInfo().getStatus().toString();
        return "green".equalsIgnoreCase(s);
    }


    /**
     * 初始化es数据类型.
     * @return boolean
     */
    public boolean createMapping(){

        final TransportClient client = EsClientUtil.getClient();
        if(client==null){
            return false;
        }

        //先创建索引
        try{
            final CreateIndexRequest request = new CreateIndexRequest(index);
            client.admin().indices().create(request).actionGet();
        }catch (final Exception e){
            //索引已存在
            LOGGER.error("创建索引错误", e);
        }

        try{
            final XContentBuilder builder=XContentFactory.jsonBuilder();
            builder.startObject()
                    .startObject("properties")
                    .startObject("id").field("type", "keyword").endObject()
                    .startObject("word").field("type", "keyword").endObject()
                    .startObject("status").field("type", "keyword").endObject()
                    .startObject("createTime").field("type", "date")
                        .field("format", "yyy-MM-dd HH:mm:ss").endObject()
                    .endObject()
                    .endObject();
            final PutMappingRequest mapping = Requests.putMappingRequest(index).type(type).source(builder);
            final PutMappingResponse putMappingResponse = client.admin().indices().putMapping(mapping).actionGet();
            return putMappingResponse.isAcknowledged();
        }catch (final Exception e){
            LOGGER.error("创建mapping错误", e);
            return false;
        }
    }

    /**
     * 查询（列表）.
     * @param qb qb
     * @return List
     */
    public List<HotWord> queryHotWord(final BoolQueryBuilder qb){
        //获取客户端
        final TransportClient client = EsClientUtil.getClient();
        if(client==null){
            return null;
        }

        //开始查询
        final SearchResponse res;
        try {
            res = client.prepareSearch(index)
                    .setTypes(type)
                    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                    .setQuery(qb)
                    .setFrom(0)
                    .setSize(10000)
                    .execute().actionGet();
        }catch (final Exception e){
            LOGGER.error("查询失败", e);
            return null;
        }

        if(res==null || res.getHits()==null){
            return null;
        }

        //获取结果
        final ArrayList<HotWord> as=new ArrayList<>();
        final JsonMapper jsonMapper = JsonMapper.buildNormalMapper();
        try {
            for (final SearchHit hit: res.getHits().getHits()){
                as.add(jsonMapper.formJson(jsonMapper.toJson(hit.getSource()), HotWord.class));
            }
        }catch (final Exception e){
            LOGGER.error("获取结果失败", e);
            return null;
        }

        //返回结果
        return as;
    }


    /**
     * 查询（列表）.
     * @param word word
     * @return List
     */
    public List<HotWord> queryHotWord(final HotWord word){
        //获取查询条件
        final BoolQueryBuilder qb = QueryBuilders.boolQuery();
        qb.filter(QueryBuilders.termQuery("word", word.getWord()));
        qb.mustNot(QueryBuilders.termQuery("id", word.getId()));
        return queryHotWord(qb);
    }

    /**
     * 查询（列表）.
     * @return List
     */
    public List<HotWord> queryHotWord(){
        //2.获取查询条件
        final BoolQueryBuilder qb = getHotWordQueryBuilder();
        return queryHotWord(qb);
    }

    /**
     * 获取查询条件.
     * @return BoolQueryBuilder
     */
    private BoolQueryBuilder getHotWordQueryBuilder(){
        //开始建立查询条件
        final BoolQueryBuilder qb = QueryBuilders.boolQuery();

        //过滤状态
        qb.filter(QueryBuilders.termsQuery("status", "0", "1"));

        return qb;
    }


    /**
     * 批量保存.
     * @param words words
     * @return boolean
     */
    public boolean saveOrUpdateBulk(final List<HotWord> words){
        final TransportClient client = EsClientUtil.getClient();
        if(client==null){
            return false;
        }
        try {
            final BulkRequestBuilder bulkRequest = client.prepareBulk();
            for (final HotWord word : words) {
                //如果word重复不添加
                if(StringUtils.isNotBlank(word.getWord()) && CollectionUtils.isNotEmpty(queryHotWord(word))){
                    continue;
                }
                if(StringUtils.isNotBlank(word.getId())){
                    bulkRequest.add(client.prepareIndex(index, type, word.getId())
                            .setSource(JsonMapper.buildNoneEmptyMapper().toJson(word),  XContentType.JSON));
                }else{
                    //es会随机生成id 不推荐
                    bulkRequest.add(client.prepareIndex(index, type)
                            .setSource(JsonMapper.buildNoneEmptyMapper().toJson(word),  XContentType.JSON));
                }
            }
            final BulkResponse bulkResponse = bulkRequest.execute().actionGet();

            if (bulkResponse.hasFailures()) {
                LOGGER.error("es批量存储失败:{}", bulkResponse.buildFailureMessage());
                return false;
            }

            bulkRequest.request().requests().clear();
            return true;
        }catch (final Exception e){
            LOGGER.error("es批量存储失败:", e);
        }
        return false;
    }


    /**
     * index库删除.
     * @return boolean
     */
    public boolean deleteAll(){
        final TransportClient client = EsClientUtil.getClient();
        if(client==null){
            return false;
        }
        try {
            final DeleteIndexResponse dResponse = client.admin().indices().prepareDelete(index)
                    .execute().actionGet();
            return dResponse.isAcknowledged();
        }catch (final Exception e){
            LOGGER.error("es索引删除失败", e);
            return false;
        }
    }

    /**
     * document删除.
     * @param id id
     * @return boolean
     */
    public boolean deleteById(final String id){
        final TransportClient client = EsClientUtil.getClient();
        if(client==null){
            return false;
        }

        try {
            final DeleteResponse dResponse = client.prepareDelete(index, type, id).execute().actionGet();
            return "deleted".equalsIgnoreCase(dResponse.getResult().name());
        }catch (final Exception e){
            LOGGER.error("删除索引失败", e);
            return false;
        }
    }

    /**
     *
     * @param word word
     * @return 是否成功
     */
    public boolean delete(final HotWord word) {
        final TransportClient client = EsClientUtil.getClient();
        if(client==null){
            return false;
        }
        try {
            final BoolQueryBuilder qb = QueryBuilders.boolQuery();
            qb.filter(QueryBuilders.termQuery("word", word.getWord()));
            final List<HotWord> words = queryHotWord(qb);
            for(final HotWord w:words){
                deleteById(w.getId());
            }
            return true;
        }catch (final Exception e){
            LOGGER.error("es索引删除失败", e);
            return false;
        }
    }
}
